package cuongnh.project.japanesediary.vocabulary.ui.view;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.property.Properties;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ObservableSetContentProvider;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.internal.PluginActionContributionItem;
import org.eclipse.wb.swt.SWTResourceManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import cuongnh.coreframework.ui.workbench.common.view.AutoUpdateView;
import cuongnh.project.japanesediary.vocabulary.common.CommonServices;
import cuongnh.project.japanesediary.vocabulary.common.CommonUtils;
import cuongnh.project.japanesediary.vocabulary.model.Category;
import cuongnh.project.japanesediary.vocabulary.model.Sentence;
import cuongnh.project.japanesediary.vocabulary.ui.common.composite.SearchComposite;

@Component("categorySentencesView")
@Scope("prototype")
public class CategorySentencesView extends AutoUpdateView implements
		ISelectionListener {
	private DataBindingContext m_bindingContext;

	public static final String ID = "cuongnh.project.japanesediary.vocabulary.ui.view.CategorySentencesView"; //$NON-NLS-1$
	private TableViewer tblvSentences;

	private SearchComposite search;
	@Autowired
	private CommonServices commonServices;
	private Category category;

	private Set<Sentence> categorySentences;

	private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());

	public CategorySentencesView() {
	}

	/**
	 * Create contents of the view part.
	 * 
	 * @param parent
	 */
	@Override
	public void createPartControl(Composite parent) {
		// add this view as a selection listener to the workbench page
		getSite().getPage().addSelectionListener((ISelectionListener) this);
		Composite container = toolkit.createComposite(parent, SWT.NONE);
		container.setBackground(SWTResourceManager
				.getColor(SWT.COLOR_WIDGET_BACKGROUND));
		toolkit.paintBordersFor(container);
		container.setLayout(new GridLayout(1, false));
		// Search control
		search = new SearchComposite(container);
		search.setBackground(SWTResourceManager
				.getColor(SWT.COLOR_WIDGET_BACKGROUND));
		search.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1,
				1));

		// Separate composite to embed the table
		Composite tableComposite = new Composite(container, SWT.NONE);
		tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				true, 1, 1));

		tblvSentences = new TableViewer(tableComposite, SWT.BORDER
				| SWT.FULL_SELECTION | SWT.MULTI);
		Table tblSentences = tblvSentences.getTable();
		tblSentences.setHeaderVisible(true);
		tblSentences.setLinesVisible(true);
		tblSentences.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
				1, 1));

		TableViewerColumn tbclvSentence = new TableViewerColumn(tblvSentences,
				SWT.NONE);
		TableColumn tbclSentence = tbclvSentence.getColumn();
		tbclSentence.setWidth(100);
		tbclSentence.setText("Sentence");

		TableViewerColumn tbclvVnMeaning = new TableViewerColumn(tblvSentences,
				SWT.NONE);
		TableColumn tbclVnMeaning = tbclvVnMeaning.getColumn();
		tbclVnMeaning.setWidth(100);
		tbclVnMeaning.setText("Vietnamese meaning");

		TableViewerColumn tbclvEnMeaning = new TableViewerColumn(tblvSentences,
				SWT.NONE);
		TableColumn tbclEnMeaning = tbclvEnMeaning.getColumn();
		tbclEnMeaning.setWidth(100);
		tbclEnMeaning.setText("English meaning");

		TableColumnLayout tbclLayout = new TableColumnLayout();
		tbclLayout.setColumnData(tbclSentence, new ColumnWeightData(30, true));
		tbclLayout.setColumnData(tbclVnMeaning, new ColumnWeightData(35, true));
		tbclLayout.setColumnData(tbclEnMeaning, new ColumnWeightData(30, true));
		tableComposite.setLayout(tbclLayout);

		// Filter
		tblvSentences.addFilter(new ViewerFilter() {
			@Override
			public boolean select(Viewer viewer, Object parentElement,
					Object element) {
				Sentence sentence = (Sentence) element;
				String text = String.valueOf(search.observeText().getValue());
				if ((sentence.getSentence() != null && sentence.getSentence()
						.toLowerCase().contains(text.toLowerCase()))
						|| (sentence.getVnMeaning() != null && sentence
								.getVnMeaning().toLowerCase()
								.contains(text.toLowerCase()))
						|| (sentence.getEnMeaning() != null && sentence
								.getEnMeaning().toLowerCase()
								.contains(text.toLowerCase()))) {
					return true;
				}

				return false;
			}

		});

		search.observeText().addChangeListener(new IChangeListener() {
			@Override
			public void handleChange(
					org.eclipse.core.databinding.observable.ChangeEvent event) {
				tblvSentences.refresh();
			}
		});

		createActions();
		initializeToolBar();
		initializeMenu();
		CommonUtils.sentencesHookDoubleClickCommand(commonServices,
				tblvSentences);
		this.hookContextMenu();
		this.setInterval(1);
		this.startAutoReload();
		initData();
		m_bindingContext = initDataBindings();
	}

	public void initData() {
		if (category != null) {
			categorySentences = commonServices.getCategoryDao()
					.getCategorySentences(category.getCategoryId());
		} else {
			categorySentences = new HashSet<Sentence>();
		}
	}

	public void refresh() {
		if (category != null) {
			categorySentences.clear();
			categorySentences.addAll(commonServices.getCategoryDao()
					.getCategorySentences(category.getCategoryId()));
			m_bindingContext.updateModels();
			tblvSentences.refresh();
		}
	}

	/**
	 * Create the actions.
	 */
	private void createActions() {
		// Create the actions
	}

	/**
	 * Initialize the toolbar.
	 */
	private void initializeToolBar() {
		IToolBarManager tbm = getViewSite().getActionBars().getToolBarManager();
	}

	/**
	 * Initialize the menu.
	 */
	private void initializeMenu() {
		IMenuManager manager = getViewSite().getActionBars().getMenuManager();
	}

	@Override
	public void setFocus() {
		// Set the focus
	}

	@Override
	public void update() {
		refresh();
	}

	@Override
	public void dispose() {
		// TODO Auto-generated method stub
		super.dispose();
	}

	@Override
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if (((StructuredSelection) selection).getFirstElement() != null) {
			if (((StructuredSelection) selection).getFirstElement() instanceof Category) {
				this.category = (Category) ((StructuredSelection) selection)
						.getFirstElement();
				update();
			}
		}

	}

	public CommonServices getCommonServices() {
		return commonServices;
	}

	public Category getCategory() {
		return category;
	}

	private void hookContextMenu() {
		MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				CategorySentencesView.this.fillContextMenu(manager);
			}
		});
		Menu menu = menuMgr.createContextMenu(tblvSentences.getControl());
		tblvSentences.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, tblvSentences);
	}

	private void fillContextMenu(IMenuManager manager) {
		IActionBars bars = getViewSite().getActionBars();

		ContributionItem item;
		for (int index = 0; index < bars.getToolBarManager().getItems().length; index++) {
			item = (ContributionItem) bars.getToolBarManager().getItems()[index];
			if (!item.isSeparator()) {
				manager.add(((PluginActionContributionItem) item).getAction());
			}

		}

		// Other plug-ins can contribute there actions here
		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
	}

	protected DataBindingContext initDataBindings() {
		DataBindingContext bindingContext = new DataBindingContext();
		//
		ObservableSetContentProvider setContentProvider = new ObservableSetContentProvider();
		IObservableMap[] observeMaps = BeansObservables.observeMaps(
				setContentProvider.getKnownElements(), Sentence.class,
				new String[] { "sentence", "vnMeaning", "enMeaning" });
		tblvSentences.setLabelProvider(new ObservableMapLabelProvider(
				observeMaps));
		tblvSentences.setContentProvider(setContentProvider);
		//
		IObservableSet selfSet = Properties.selfSet(Sentence.class).observe(
				categorySentences);
		tblvSentences.setInput(selfSet);
		//
		return bindingContext;
	}

	public Set<Sentence> getSelectedSentences() {
		Set<Sentence> selectedSentences = new HashSet<Sentence>();
		StructuredSelection sel = (StructuredSelection) tblvSentences
				.getSelection();
		for (Iterator<Sentence> iter = sel.iterator(); iter.hasNext();) {
			selectedSentences.add(iter.next());
		}

		return selectedSentences;
	}

	public TableViewer getTblvSentences() {
		return tblvSentences;
	}
}
